home *** CD-ROM | disk | FTP | other *** search
- /*
- * V(oronoi)A(nalysis)
- *
- * routines to analyze Voronoi diagram, given in file of type .vdt,
- * generated by xvor.c
- *
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "vora.h"
-
-
- /* global */
- int EDGE_SORT = 0;
- struct Tuple em;
- extern int ACTIVE_AOI;
-
-
- #define EPS 0.1 /* lower limit for poly edge length */
- /* an edge of len < 1 pix will not */
- /* appear on the display */
-
- /*
- * hsbaird macros (for later use)
- */
- #define AREA(a,b,c) ( ((-((c)->y-(b)->y))*((a)->x-(b)->x)+((c)->x-(b)->x)*((a)->y-(b)->y)) )
-
- /*
- * macroes for use within winding order function
- */
- /* dot product */
- #define DOT(a,b) ( (a).x*(b).x+(a).y*(b).y )
-
- /* perp product */
- #define PERP(a,b) ( -((a).y)*(b).x+(a).x*(b).y )
-
- /*
- * return the quadrant no: 0,1,2,3 of pt `a' wrt to the X-Y coordinate system
- * defined by aligning the positive X-axis along vector `o' (`a' is a vector
- * wrt to `o')
- */
- #define QUAD(a,o) ( ((DOT((o),(a)))>=0) ? ( (PERP((o),(a))>=0) ? 0 : 3) : ( (PERP((o),(a))>=0) ? 1 : 2) )
-
-
- /*
- * return -1,0,1 as pt `a' is less than, equal to, or greater than pt `b' in
- * counterclockwise winding order about an (implicit) center `HULL_c', where
- * the vector `o' defines the `origin' direction
- */
- int qa, qb;
- struct Pix o;
- #define WIND(a,b,o) ( ((qa=QUAD((a),(o))) == (qb=QUAD((b),(o)))) ? SIGN(PERP((a),(b))) : SIGN(qb-qa) )
-
-
-
- #undef SHOW_SORT
-
-
- /*
- * evaluate edge midpoint coordinates
- */
- struct Tuple *
- edge_mp (v1, v2, index)
- struct vSite *v1, *v2;
- int index;
- {
- struct Tuple *emp = &em;
-
- emp->x = (float) 0.5 *(v1->coord.x + v2->coord.x);
- emp->y = (float) 0.5 *(v1->coord.y + v2->coord.y);
- emp->index = index;
-
- return (emp);
- }
-
-
- /*
- * winding number function, for use in edge sort
- */
- int
- winding_ccwT (r1, r2)
- struct Tuple *r1, *r2;
- {
- struct Pix a, b;
-
- a.x = r1->x;
- a.y = r1->y;
- b.x = r2->x;
- b.y = r2->y;
-
- return (WIND (a, b, o));
- }
-
- /*
- * sort polygon edges;
- * the implementation is adapted from h. s. baird (->p_app.c): it relies
- * on a sort with respect to ``winding number'' and employs the macros
- * defined above; a site interior to the polygon is needed: this is
- * the orig. site *s;
- */
- void
- sort_poly_edges (pem, s, p)
- struct Tuple *pem;
- struct vSite *s;
- struct vPoly *p;
- {
-
- /*define ``origin'' vector, from interior point *s to 1st pt */
- o.x = pem->x - s->coord.x;
- o.y = pem->y - s->coord.y;
-
- #if defined(LINUX)
- qsort (pem, p->ne, sizeof (struct Tuple *), (__compar_fn_t) winding_ccwT);
- #else
- qsort (pem, p->ne, sizeof (struct Tuple *), winding_ccwT);
- #endif
-
-
- /*
- * use the reordered sequence of polygon edges...
- */
-
- }
-
-
-
- /*
- * comparison function for qsort():
- * sort array of edges in order of increasing site indices, sO, sF
- */
- int
- esO_comp (e1, e2)
- struct vEdge *e1, *e2;
- {
-
- if (e1->sO < e2->sO)
- return (-1);
- if (e1->sO > e2->sO)
- return (1);
-
- return (0);
- }
-
- /*
- * comparison function for qsort():
- * sort array of edges in order of increasing site indices, sO, sF
- */
- int
- esF_comp (e1, e2)
- struct vEdge *e1, *e2;
- {
-
- if (e1->sF < e2->sF)
- return (-1);
- if (e1->sF > e2->sF)
- return (1);
-
- return (0);
- }
-
-
- /*
- * determine length of a given line segment,
- * i. e. Voronoi edge or bisector
- */
- double
- slen (v1, v2)
- struct vSite *v1, *v2;
- {
- double len;
- double dx, dy;
-
- dx = (double) (v1->coord.x - v2->coord.x);
- dy = (double) (v1->coord.y - v2->coord.y);
- len = sqrt (dx * dx + dy * dy);
- if ((-EPS < len) && (len < EPS))
- len = 0.0;
-
- return (len);
- }
-
-
-
-
- /*
- * analyze site properties; return max coodination number in set
- *
- * note:
- * (s+is)->nnn is being redetermined here: this is not necessary
- * (see site_coordination()) and should be improved; ms, 4/94;
- *
- * sites are presumed ta have been examined (in mark_eSites() and
- * in site_coordination()) for edge conditions
- */
- int
- site_geom (struct vSite *s, struct vSite *v, struct vEdge *e, struct vPoly *p, int ns, int ne)
- {
- int ie, is;
- int e_vO, e_vF;
- int efl, lfl;
- double vE_len;
-
- int max_ne;
-
- /*
- * search sF member, assumed sorted (see site_coordination())
- */
- ie = 0;
- for (is = 0; is < ns; is++) { /* loop over sites */
- (s + is)->nnn = 0; /* count not nn sites */
- (p + is)->ne = 0; /* count nof Vpoly edges */
- (p + is)->sitenbr = (s + is)->sitenbr;
- (p + is)->aoiFlag = (s + is)->aoiFlag;
- (p + is)->eFlag = (p + is)->lFlag = UnSet;
-
- /*
- * search sF member
- */
- efl = lfl = 0;
- while ((e + ie)->sF == (s + is)->sitenbr) {
- (s + is)->nnd[(s + is)->nnn] = (float) slen (s + ((e + ie)->sO), s + ((e + ie)->sF));
- (s + is)->nnsi[(s + is)->nnn] = (e + ie)->sO;
- (s + is)->nnn++;
-
- (p + is)->pei[(p + is)->ne] = (e + ie)->edgenbr;
- e_vO = (e + ie)->vO;
- e_vF = (e + ie)->vF;
- if (check_e (e_vO, e_vF) == Set) {
- (p + is)->vel[(p + is)->ne] = (float) -1.0;
- efl++;
- }
- else {
- if ((vE_len = slen (v + e_vO, v + e_vF)) == 0.0) {
- (p + is)->vel[(p + is)->ne] = (float) -1.0;
- lfl++;
- }
- else { /* edge too small to display */
- (p + is)->vel[(p + is)->ne] = (float) vE_len;
- if (vE_len <= 1.0)
- lfl++;
- }
- }
- (p + is)->ne++;
- ie++;
- }
- if (efl > 0)
- (p + is)->eFlag = Set;
- if (lfl > 0)
- (p + is)->lFlag = Set;
- }
-
-
- /*
- * now, search sO member
- */
- #if defined(LINUX)
- qsort (e, ne, sizeof (struct vEdge), (__compar_fn_t) esO_comp);
- #else
- qsort (e, ne, sizeof (struct vEdge), esO_comp);
- #endif
- #ifdef SHOW_SORT
- printf ("\n...edges after sorting in order of sO indices:\n");
- for (ie = 0; ie < ne; ie++)
- printf (" e %3d: vO: %3d vF: %3d sO: %3d sF: %3d\n",
- (e + ie)->edgenbr, (e + ie)->vO, (e + ie)->vF, (e + ie)->sO, (e + ie)->sF);
- #endif
-
- ie = 0;
- for (is = 0; is < ns; is++) {
- efl = lfl = 0;
- while ((e + ie)->sO == (s + is)->sitenbr) {
- (s + is)->nnd[(s + is)->nnn] = (float) slen (s + ((e + ie)->sO), s + ((e + ie)->sF));
- (s + is)->nnsi[(s + is)->nnn] = (e + ie)->sF;
- (s + is)->nnn++;
-
- (p + is)->pei[(p + is)->ne] = (e + ie)->edgenbr;
- e_vO = (e + ie)->vO;
- e_vF = (e + ie)->vF;
- if (check_e (e_vO, e_vF) == Set) {
- (p + is)->vel[(p + is)->ne] = (float) -1;
- efl++;
- }
- else {
- if ((vE_len = slen (v + e_vO, v + e_vF)) == 0.0) {
- (p + is)->vel[(p + is)->ne] = (float) -1.0;
- lfl++;
- }
- else { /* edge too small to display */
- (p + is)->vel[(p + is)->ne] = (float) vE_len;
- if (vE_len <= 1.0)
- lfl++;
- }
- }
- (p + is)->ne++;
- ie++;
- }
- if (efl > 0)
- (p + is)->eFlag = Set;
- if (lfl > 0)
- (p + is)->lFlag = Set;
- }
-
- /*
- * determine max coordination number
- */
- max_ne = 0;
- for (is = 0; is < ns; is++)
- if ((p + is)->ne > max_ne)
- max_ne = (p + is)->ne;
-
- return (max_ne);
- }
-
-
-
-
- /*
- * comparison function for qsort():
- * sort array of edges in order of increasing edge index
- */
- int
- e_comp (e1, e2)
- struct vEdge *e1, *e2;
- {
-
- if (e1->edgenbr < e2->edgenbr)
- return (-1);
- if (e1->edgenbr > e2->edgenbr)
- return (1);
-
- return (0);
- }
-
-
- /*
- * determine (signed) triangular area spanned by three supplied vertices
- */
- double
- T_area (v1, v2, v3)
- struct vSite *v1, *v2, *v3;
- {
- double s_area;
- double x1, x2, x3, y1, y2, y3;
-
- x1 = (double) (v1->coord.x);
- x2 = (double) (v2->coord.x);
- x3 = (double) (v3->coord.x);
- y1 = (double) (v1->coord.y);
- y2 = (double) (v2->coord.y);
- y3 = (double) (v3->coord.y);
-
- s_area = (x1 * y2 - x2 * y1) + (x2 * y3 - x3 * y2) + (x3 * y1 - x1 * y3);
- if ((-1.0e-10 < s_area) && (s_area < 1.0e-10))
- s_area = 0.0;
-
- return (s_area);
- }
-
-
- /*
- * check whether vertices defining edge are set to -1;
- * if so, set flag to Set status, otherwise, return UnSet;
- */
- Boolean
- check_e (e_vO, e_vF)
- int e_vO, e_vF;
- {
-
- if ((e_vO == -1) || (e_vF == -1))
- return (Set);
-
- return (UnSet);
- }
-
-
- /*
- * mark edges crossing ``active'' AOI bounds,
- * set aoiFlags for out-of-bounds edge endpoints
- */
- void
- mark_eEdges (struct vSite *v, struct vEdge *e, int ne)
- {
- int ie;
- int e_vO, e_vF;
-
- for (ie = 0; ie < ne; ie++) {
- e_vO = (e + ie)->vO;
- e_vF = (e + ie)->vF;
- if (check_e (e_vO, e_vF) == UnSet) {
- if (((v + e_vO)->aoiFlag = check_v (v + e_vO)) == Set)
- (e + ie)->vO = -1;
- if (((v + e_vF)->aoiFlag = check_v (v + e_vF)) == Set)
- (e + ie)->vF = -1;
- }
- }
- }
-
-
-
- /*
- * joint probability distribution, p(n, A)
- * construct joint probability distribution, p(n, A), of poly edge number
- * n, and Voronoi polygon area, A (see p_of_nA(), anal_gt.c)
- */
- double
- p_of_nVA (int *npn, unsigned int **a_n, int ns, struct vPoly *p)
- {
- int is, cne;
- int nma;
- double ma;
-
- nma = 0;
- ma = 0.0;
- for (is = 0; is < ns; is++) {
- if (((p + is)->aoiFlag == UnSet) &&
- ((p + is)->eFlag == UnSet) &&
- ((p + is)->lFlag == UnSet)) {
- cne = (p + is)->ne;
- *(a_n[cne] + npn[cne]) = (unsigned int) (p + is)->area;
- npn[cne]++;
-
- ma += (p + is)->area;
- nma++;
- }
- }
- ma /= (double) nma;
- return (ma);
- }
-
-
- /*
- * determine number of (unflagged) polygons,
- * with edge numbers between nel and neu;
- *
- * nea array index: i = (ne = (p+is)->ne) - nel;
- */
- int *
- pe_dist (struct vPoly *p, int ns, int nel, int neu)
- {
- int is, ne;
- int *nea;
-
- if ((nea = (int *) calloc (16, sizeof (int))) == NULL)
- fail_alloc ("nea", 1);
-
- for (is = 0; is < ns; is++) {
- if (((p + is)->eFlag == UnSet) &&
- ((p + is)->lFlag == UnSet)) {
- if ((ne = (p + is)->ne) < 16)
- nea[ne]++;
- }
- }
- return (nea);
- }
-
-
- /*
- * polygon associated site, area, etc
- */
- void
- poly_geom (struct vSite *s, struct vSite *v, struct vEdge *e, struct vPoly *p, struct Tuple *pem, int ns, int ne, int CPV)
- {
- int ie, is;
- int e_vO, e_vF;
- #if BOND
- Boolean eFlag;
- double l1, l2;
- #endif
- double sarea;
-
-
- /*
- * sort edge structure in order of increasing edge index
- */
- #if defined(LINUX)
- qsort (e, ne, sizeof (struct vEdge), (__compar_fn_t) e_comp);
- #else
- qsort (e, ne, sizeof (struct vEdge), e_comp);
- #endif
- #ifdef SHOW_SORT
- printf ("\n...edges after sorting in order of edge indices:\n");
- for (i = 0; i < ne; i++)
- printf (" e %3d: vO: %3d vF: %3d sO: %3d sF: %3d\n",
- (e + i)->edgenbr, (e + i)->vO, (e + i)->vF, (e + i)->sO, (e + i)->sF);
- #endif
-
-
- /*
- * evaluate V. polygon area and set of angles subtended by edges
- * if desired, collect (valid) indices of polygon vertices
- */
- for (is = 0; is < ns; is++) { /* loop over polygons: one per site */
- (p + is)->coord.x = (s + is)->coord.x;
- (p + is)->coord.y = (s + is)->coord.y;
- (p + is)->area = (float) 0.0;
- for (ie = 0; ie < (p + is)->ne; ie++) { /* loop over poly edges */
- e_vO = (e + ((p + is)->pei[ie]))->vO;
- e_vF = (e + ((p + is)->pei[ie]))->vF;
- if (check_e (e_vO, e_vF) == UnSet) {
- sarea = T_area ((v + e_vF), (v + e_vO), (s + is));
- (p + is)->area += (float) (fabs (0.5 * sarea));
-
- if (CPV == 1) {
- if (SIGN (sarea) < 0)
- (p + is)->pvi[ie] = e_vO;
- else
- (p + is)->pvi[ie] = e_vF;
- }
- /* (pem+ie) = edge_mp(v+e_vF, v+e_vO, ie); */
- }
- else {
- (p + is)->pvi[ie] = -1;
- }
- }
-
- /*
- * sort polygon edges to determine nn `bond' angles
- */
-
- #if BOND
- if (eFlag == UnSet) {
- sort_poly_edges (pem, s + is, p + is);
-
- for (ie = 0; ie < (p + is)->ne; ie++) {
- sarea = T_area ((), (), (s + is));
-
- l1 = slen (pem + ie, s + is);
- l2 = slen (pem + ie + 1, s + is);
- (p + is)->sphi[ie] = (float) sarea / (l1 * l2);
- }
- }
- #endif
- }
- }
-
- /*
- * check whether site lies outside AOI; if so, return Set;
- * (same as function check_v())
- */
- Boolean
- check_s (s)
- struct vSite *s;
- {
- int sx, sy;
-
- sx = (int) s->coord.x;
- sy = (int) s->coord.y;
- if (sx < AULX)
- return (Set);
- if (sy < AULY)
- return (Set);
- if (sx > ALRX)
- return (Set);
- if (sy > ALRY)
- return (Set);
-
- return (UnSet);
- }
-
- /*
- * set aoiFlag for all Sites which fall outside of ``active'' AOI
- */
- void
- mark_eSites (s, ns)
- struct vSite *s;
- int ns;
- {
- int is;
-
- for (is = 0; is < ns; is++)
- (s + is)->aoiFlag = check_s ((s + is));
- }
-
-
- /*
- * determine number of sites, within ``active'' AOI,
- * with coordination numbers between ncl and ncu;
- *
- * nnna array index: i = (nc = (s+is)->nnn) - ncl;
- */
- int *
- count_defects (s, ns, ncl, ncu)
- struct vSite *s;
- int ns, ncl, ncu;
- {
- int is;
- int nc;
- int *nnna;
-
- if ((nnna = (int *) calloc (16, sizeof (int))) == NULL)
- fail_alloc ("nnna", 1);
-
- for (is = 0; is < ns; is++) {
- if (((s + is)->eFlag == UnSet) &&
- ((s + is)->aoiFlag == UnSet)) {
- if ((nc = (s + is)->nnn) < 16)
- nnna[nc]++;
- }
- }
- return (nnna);
- }
-
-
- /*
- * check whether vertex lies outside AOI; if so, return Set;
- * (same as function check_s())
- */
- Boolean
- check_v (v)
- struct vSite *v;
- {
- int vx, vy;
-
- vx = (int) v->coord.x;
- vy = (int) v->coord.y;
-
- if (ACTIVE_AOI == 1) { /* enforce new AOI bounds */
- if (vx < AULX)
- return (Set);
- if (vy < AULY)
- return (Set);
- if (vx > ALRX)
- return (Set);
- if (vy > ALRY)
- return (Set);
- }
- else { /* enforce orig display AOI bounds */
- if (vx < ULX)
- return (Set);
- if (vy < ULY)
- return (Set);
- if (vx > LRX)
- return (Set);
- if (vy > LRY)
- return (Set);
- }
- return (UnSet);
- }
-
-
- /*
- * determine site coordination:
- * this is given by the number of edges of non-zero length associated
- * with a given site in such a way that their bisectors share one common
- * vertex, namely the site in question;
- *
- * mark ``edge'' sites, by setting eFlag:
- * these are sites whose associated V. polygon contains vertices
- * which lie outside the display AOI: this includes those vertices
- * connected by edges marked -1 in struct e;
- *
- * the following routine assumes the vEdge array to be suitably sorted;
- */
- void
- site_coordination (s, v, e, ns, ne)
- struct vSite *s, *v;
- struct vEdge *e;
- int ns, ne;
- {
- int ie, is;
- int e_vO, e_vF;
- int efl;
-
-
- /*
- * first, search sO member
- */
- #if defined(LINUX)
- qsort (e, ne, sizeof (struct vEdge), (__compar_fn_t) esO_comp);
- #else
- qsort (e, ne, sizeof (struct vEdge), esO_comp);
- #endif
- #ifdef SHOW_SORT
- printf ("\n...edges after sorting in order of sO indices:\n");
- for (i = 0; i < ne; i++)
- printf (" e %3d: vO: %3d vF: %3d sO: %3d sF: %3d\n",
- (e + i)->edgenbr, (e + i)->vO, (e + i)->vF, (e + i)->sO, (e + i)->sF);
- #endif
- printf ("\n");
- ie = 0;
- for (is = 0; is < ns; is++) {
- efl = 0;
- while ((e + ie)->sO == (s + is)->sitenbr) {
- (s + is)->nnn++;
-
- e_vO = (e + ie)->vO;
- e_vF = (e + ie)->vF;
- if (check_e (e_vO, e_vF) == Set)
- efl++;
-
- ie++;
- }
- if (efl > 0)
- (s + is)->eFlag = Set;
- }
- printf ("\n");
-
- /*
- * now, search sF member
- */
- #if defined(LINUX)
- qsort (e, ne, sizeof (struct vEdge), (__compar_fn_t) esF_comp);
- #else
- qsort (e, ne, sizeof (struct vEdge), esF_comp);
- #endif
- #ifdef SHOW_SORT
- printf ("\n...edges after sorting in order of sF indices:\n");
- for (i = 0; i < ne; i++)
- printf (" e %3d: vO: %3d vF: %3d sO: %3d sF: %3d\n",
- (e + i)->edgenbr, (e + i)->vO, (e + i)->vF, (e + i)->sO, (e + i)->sF);
- #endif
-
- ie = 0;
- for (is = 0; is < ns; is++) {
- efl = 0;
- while ((e + ie)->sF == (s + is)->sitenbr) {
- (s + is)->nnn++;
-
- e_vO = (e + ie)->vO;
- e_vF = (e + ie)->vF;
- if (check_e (e_vO, e_vF) == Set)
- efl++;
-
- ie++;
- }
- if (efl > 0)
- (s + is)->eFlag = Set;
- }
- }
-